home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- From: Liudvikas Bukys <bukys@cs.rochester.edu>
- Subject: v22i001: average - average data in multiple input files, Part01/01
- Message-ID: <1991Aug13.035017.23751@sparky.IMD.Sterling.COM>
- X-Md4-Signature: 147533dbf9bb4ac79efb6e07d2becee7
- Date: Tue, 13 Aug 1991 03:50:17 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: Liudvikas Bukys <bukys@cs.rochester.edu>
- Posting-number: Volume 22, Issue 1
- Archive-name: average/part01
- Environment: UNIX
-
- I wrote this years ago, and a colleague liked it so much that I wrote
- a man page and a Makefile and now it's in your hands.
-
- average produces a composite data file from many similar input files.
- average takes multiple files containing text (which should be the
- same in all files) and numbers (which may differ from file to file),
- and it outputs one file, with the same text, and with each occurence
- of a number replaced by its average over all of the input files.
-
- I find this program useful for averaging the timing output from several
- runs of a program.
-
- Liudvikas Bukys
- <bukys@cs.rochester.edu>
- ---
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: average.1 average.c Makefile
- # Wrapped by bukys@stork.cs.rochester.edu on Fri Aug 9 12:20:26 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'average.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'average.1'\"
- else
- echo shar: Extracting \"'average.1'\" \(1370 characters\)
- sed "s/^X//" >'average.1' <<'END_OF_FILE'
- X.TH AVERAGE 1 "31 March 1987"
- X.SH NAME
- Xaverage \- produce a composite data file from many similar data files
- X.SH SYNOPSIS
- X.B average
- X.RB [ " \-m " ]
- X.IR filename \&.\|.\|.
- X.SH DESCRIPTION
- X.IX "average command" "" "\fLaverage\fP \(em produce a composite data file from many similar data files"
- X.LP
- X.B average
- Xtakes multiple files containing
- Xtext (which should be the same in all files) and numbers (which
- Xmay differ from file to file), and it outputs one file, with
- Xthe same text, and with each occurence of a number replaced
- Xby its average over all of the input files.
- X.LP
- XThe numbers are output with precision matching the maximum precision
- Xpresent in the input, so integers remain integers, numbers with
- Xsix digits to the right of the decimal point will continue to be
- Xoutput with six digits, etc.
- X.LP
- XThe author finds this program useful for averaging the timing output
- Xfrom several runs of a program.
- X.SH OPTIONS
- X.TP
- X.B \-m
- XFor numbers whose values vary over the input files, output
- Xa [min,average,max] tuple instead of a single number.
- X.SH BUGS
- X.LP
- XThere is no support for numbers with 'e', 'E', or '+' in them
- X(e.g., numbers with exponents).
- X.LP
- XThe whole file is constructed in memory, which is not strictly
- Xnecessary, as the first file could be rescanned instead.
- X.SH AUTHOR
- X.LP
- XLiudvikas Bukys
- X<bukys@cs.rochester.edu>
- X.\" This code is in the public domain.
- END_OF_FILE
- if test 1370 -ne `wc -c <'average.1'`; then
- echo shar: \"'average.1'\" unpacked with wrong size!
- fi
- # end of 'average.1'
- fi
- if test -f 'average.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'average.c'\"
- else
- echo shar: Extracting \"'average.c'\" \(5247 characters\)
- sed "s/^X//" >'average.c' <<'END_OF_FILE'
- X/*
- X * average -- produce a composite file from multiple, similar, files
- X *
- X * This general-purpose program takes multiple files containing
- X * text (which should be the same in all files) and numbers (which
- X * may differ from file to file), and it outputs one file, with
- X * the same text, and with each occurence of a number replaced
- X * by its average over all of the input files. There is an option
- X * for outputting [min,average,max] tuples instead of a single number.
- X *
- X * HISTORY
- X *
- X * 1987/03/31 Liudvikas Bukys <bukys@cs.rochester.edu>
- X *
- X * Version 1.0 created.
- X *
- X * I needed it to compute some average runtimes from several
- X * timing runs of some multiprocessor code.
- X *
- X * There is no support for numbers with 'e', 'E', or '+' in
- X * them. Those characters would be parsed as text.
- X *
- X * The whole file is sucked into memory.
- X */
- X
- X#define USAGE "USAGE: %s [-m] file1 [file2 ...]\n"
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- Xextern char *malloc();
- Xextern char *strchr(); /* or try index() if you don't have strchr() */
- X
- X#define MAX(a,b) (((a)>(b))?(a):(b))
- X#define MIN(a,b) (((a)<(b))?(a):(b))
- X
- Xstruct token
- X {
- X struct token *next;
- X char *buffer;
- X int precision;
- X double average, min, max;
- X int count;
- X } head = { 0, };
- X
- X/*
- X * MAXTOKENLEN doesn't show through to the user, who doesn't care whether
- X * a bunch of text is parsed as a single 20000-byte token or a pile of
- X * 512-byte tokens. The only thing it might affect would be if you had
- X * numbers with length > MAXTOKENLEN, but this code doesn't have any
- X * bignum support anyway.
- X */
- X#define MAXTOKENLEN 512
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X {
- X register int i;
- X register FILE *f;
- X register struct token *p;
- X int minmaxflag = 0;
- X
- X if (argc <= 1)
- X {
- X (void) fprintf(stderr, USAGE, argv[0]);
- X exit(1);
- X }
- X
- X /*
- X * Read in each of my input files and tokenize it.
- X */
- X for (i= 1; i < argc; i++)
- X if (argv[i][0] == '-')
- X if (argv[i][1] == 'm')
- X minmaxflag = 1;
- X else
- X {
- X (void) fprintf(stderr, USAGE, argv[0]);
- X exit(1);
- X }
- X else if ((f= fopen(argv[i], "r")) != NULL)
- X {
- X for (p= &head; !feof(f); p= p->next)
- X readword(p, f);
- X (void) fclose(f);
- X }
- X else
- X perror(argv[i]);
- X
- X /*
- X * Output the token list.
- X * Numbers retain the maximum precision of the input numbers.
- X */
- X for (p = head.next; p; p = p->next)
- X if (p->buffer)
- X (void) printf("%s", p->buffer);
- X else if (p->precision == 0)
- X if (p->min == p->max)
- X (void) printf("%d", (int) p->min);
- X else if (minmaxflag)
- X (void) printf("[%d %d %d]", (int) p->min, (int) p->average, (int) p->max);
- X else
- X (void) printf("%d", (int) p->average);
- X else
- X if (p->min == p->max)
- X (void) printf("%.*lf", p->precision-1, p->min);
- X else if (minmaxflag)
- X (void) printf("[%.*lf %.*lf %.*lf]",
- X p->precision-1, p->min,
- X p->precision-1, p->average,
- X p->precision-1, p->max);
- X else
- X (void) printf("%.*lf", p->precision-1, p->average);
- X
- X exit (0);
- X }
- X
- X/*
- X * Read one token -- either a number or a text string.
- X */
- Xreadword(ptail, f)
- Xstruct token *ptail;
- XFILE *f;
- X {
- X register struct token *p;
- X register int c, hasdigit, wasseparator;
- X register unsigned len;
- X char tok[MAXTOKENLEN+1];
- X
- X /*
- X * get next token, or add a new one to the end of the list
- X */
- X if (p= ptail->next)
- X ;
- X else if (ptail->next = p = (struct token *) malloc(sizeof *p))
- X {
- X p->next = 0;
- X p->buffer = 0;
- X p->count = 0;
- X p->precision = 0;
- X }
- X else
- X {
- X (void) fprintf(stderr, "malloc failed\n");
- X exit(1);
- X }
- X
- X c = getc(f);
- X (void) ungetc(c, f);
- X if (strchr("0123456789.-", c))
- X {
- X /*
- X * possibly data -- defer judgement until after I see some
- X * digits (this might just be a string of '-', after all).
- X */
- X len = 0;
- X hasdigit = 0;
- X while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
- X if (strchr("0123456789.-", c))
- X {
- X tok[len++] = c;
- X if (strchr("0123456789", c))
- X hasdigit = 1;
- X }
- X else
- X {
- X (void) ungetc(c, f);
- X break;
- X }
- X tok[len] = '\0';
- X if (hasdigit)
- X dodata(p, tok, len);
- X else
- X dotext(p, tok, len);
- X }
- X else
- X {
- X /*
- X * text
- X */
- X wasseparator = 0;
- X len = 0;
- X while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
- X if (wasseparator && strchr("0123456789.-", c))
- X {
- X (void) ungetc(c, f);
- X break;
- X }
- X else
- X {
- X tok[len++] = c;
- X wasseparator = !isascii(c) || !isalnum(c);
- X }
- X tok[len] = '\0';
- X dotext(p, tok, len);
- X }
- X }
- X
- X/*
- X * Do number-specific processing -- compute min, max, average
- X */
- Xdodata(p, tok, len)
- Xstruct token *p;
- Xchar *tok;
- Xunsigned len;
- X {
- X char *dot;
- X double value;
- X
- X if (dot= strchr(tok, '.'))
- X p->precision = MAX(p->precision, (tok+len)-dot);
- X
- X value = 0.0;
- X (void) sscanf(tok, "%lf", &value);
- X
- X if (p->count++)
- X {
- X p->min = MIN(p->min, value);
- X p->max = MAX(p->max, value);
- X p->average = p->average*((p->count-1.0)/(p->count)) + value/p->count;
- X }
- X else
- X p->min = p->max = p->average = value;
- X }
- X
- X/*
- X * Do text-specific processing -- save the text permanently (but only the first time!)
- X */
- Xdotext(p, tok, len)
- Xstruct token *p;
- Xchar *tok;
- Xunsigned len;
- X {
- X if (p->buffer)
- X ; /* remember the old string only */
- X else if (p->buffer= malloc(len+1))
- X bcopy(tok, p->buffer, len+1);
- X else
- X {
- X (void) fprintf(stderr, "malloc failed\n");
- X exit(1);
- X }
- X }
- END_OF_FILE
- if test 5247 -ne `wc -c <'average.c'`; then
- echo shar: \"'average.c'\" unpacked with wrong size!
- fi
- # end of 'average.c'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(111 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- Xall: average
- X
- Xclean:
- X rm -f average average.o
- X
- X#####
- X
- Xaverage: average.o
- X $(CC) $(CFLAGS) -o average average.o
- END_OF_FILE
- if test 111 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- echo shar: End of shell archive.
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-